#ifndef TREES_H
#define TREES_H

enum node_type {
	NODE_RETURN, NODE_TWO_VALUES, NODE_OPCODE, NODE_OPCODE_1, NODE_OPCODE_2,
	NODE_UNARY_OP, NODE_UNARY_OP_1, NODE_BINARY_OP,
	NODE_CONTROL_JUMP, NODE_LOOP,
	NODE_CALL, NODE_CALL_1, NODE_LAND_LOR, NODE_FOREACH,
	NODE_IF, NODE_BRANCH_LINK,
	NODE_EFUN, NODE_REAL, NODE_NUMBER,
	NODE_STRING,
	NODE_FUNCTION
};

enum control_jump_type {
	CJ_BREAK = 0, CJ_CONTINUE = 1
};

union parse_value {
	int number;
	float real;
	struct parse_node_s *expr;
};

typedef struct parse_node_s {
	short kind;
	short line;
	unsigned char type;
	union parse_value v, l, r; /* left, right, and value */
} parse_node_t;

#define IS_NODE(vn, nt, op) ((vn)->kind == nt && (vn)->v.number == op)

#define CREATE_RETURN(vn, val) SAFE(\
		(vn) = new_node_no_line();\
		(vn)->kind = NODE_RETURN;\
		(vn)->r.expr = val;\
		)
#define CREATE_STATEMENTS(vn, ln, rn) SAFE(\
		(vn) = new_node_no_line();\
		(vn)->kind = NODE_TWO_VALUES;\
		(vn)->l.expr = ln;\
		(vn)->r.expr = rn;\
		)
#define CREATE_TWO_VALUES(vn, t, ln, rn) SAFE(\
		CREATE_STATEMENTS(vn, ln, rn);\
		(vn)->type = t;\
		)
#define INT_CREATE_OPCODE(vn, op, t) SAFE(\
		(vn)->v.number = op;\
		(vn)->type = t;\
		)
#define CREATE_OPCODE(vn, op, t) SAFE(\
		(vn) = new_node();\
		(vn)->kind = NODE_OPCODE;\
		INT_CREATE_OPCODE(vn, op, t);\
		)
#define CREATE_OPCODE_1(vn, op, t, p) SAFE(\
		(vn) = new_node();\
		(vn)->kind = NODE_OPCODE_1;\
		INT_CREATE_OPCODE(vn, op, t);\
		(vn)->l.number = p;\
		)
#define CREATE_OPCODE_2(vn, op, t, p1, p2) SAFE(\
		(vn) = new_node();\
		(vn)->kind = NODE_OPCODE_2;\
		INT_CREATE_OPCODE(vn, op, t);\
		(vn)->l.number = p1;\
		(vn)->r.number = p2;\
		)
#define INT_CREATE_UNARY_OP(vn, op, t, x) SAFE(\
		INT_CREATE_OPCODE(vn, op, t);\
		(vn)->r.expr = x;\
		)
#define CREATE_UNARY_OP(vn, op, t, x) SAFE(\
		(vn) = new_node();\
		(vn)->kind = NODE_UNARY_OP;\
		INT_CREATE_UNARY_OP(vn, op, t, x);\
		)
#define CREATE_UNARY_OP_1(vn, op, t, x, p) SAFE(\
		(vn) = new_node();\
		(vn)->kind = NODE_UNARY_OP_1;\
		INT_CREATE_UNARY_OP(vn,\
			op, t, x);\
		(vn)->l.number = p;\
		)
#define INT_CREATE_BINARY_OP(vn, op, t, x, y) SAFE(\
		INT_CREATE_UNARY_OP(vn, op,\
			t, y);\
		(vn)->l.expr = x;\
		)
#define CREATE_BINARY_OP(vn, op, t, x, y) SAFE(\
		(vn) = new_node();\
		(vn)->kind = NODE_BINARY_OP;\
		INT_CREATE_BINARY_OP(vn, op,\
			t, x, y);\
		)
#define CREATE_CONTROL_JUMP(vn, op) SAFE(\
		(vn) = new_node_no_line();\
		(vn)->kind = NODE_CONTROL_JUMP;\
		(vn)->v.number = op;\
		)
#define CREATE_LOOP(vn, tf, b, i, t) SAFE(\
		(vn) = new_node_no_line();\
		(vn)->kind = NODE_LOOP;\
		(vn)->type = tf;\
		(vn)->v.expr = b;\
		(vn)->l.expr = i;\
		(vn)->r.expr = t;\
		)
#define CREATE_CALL(vn, op, t, el) SAFE(\
		(vn) = el;\
		(vn)->kind = NODE_CALL;\
		(vn)->l.number = (vn)->v.number;\
		(vn)->v.number = op;\
		(vn)->type = t;\
		)
#define CREATE_LAND_LOR(vn, op, x, y) SAFE(\
		(vn) = new_node();\
		(vn)->kind = NODE_LAND_LOR;\
		(vn)->v.number = op;\
		(vn)->l.expr = x;\
		(vn)->r.expr = y;\
		(vn)->type = ((x->type == y->type)\
			? x->type : TYPE_ANY);\
		)
#define CREATE_FOREACH(vn, ln, rn) SAFE(\
		(vn) = new_node();\
		(vn)->kind = NODE_FOREACH;\
		(vn)->l.expr = ln;\
		(vn)->r.expr = rn;\
		)
#define CREATE_IF(vn, c, s, e) SAFE(\
		(vn) = new_node_no_line();\
		(vn)->kind = NODE_IF;\
		(vn)->v.expr = c;\
		(vn)->l.expr = s;\
		(vn)->r.expr = (e);\
		)
#define CREATE_REAL(vn, val) SAFE(\
		(vn) = new_node_no_line();\
		(vn)->kind = NODE_REAL;\
		(vn)->type = TYPE_REAL;\
		(vn)->v.real = val;\
		)
#define CREATE_NUMBER(vn, val) SAFE(\
		(vn) = new_node_no_line();\
		(vn)->kind = NODE_NUMBER;\
		(vn)->type = (val ? TYPE_NUMBER : TYPE_ANY);\
		(vn)->v.number = val;\
		)
#define CREATE_STRING(vn, val) SAFE(\
		(vn) = new_node_no_line();\
		(vn)->kind = NODE_STRING;\
		(vn)->type = TYPE_STRING;\
		(vn)->v.number = store_prog_string(val);\
		)
#define CREATE_ERROR(vn) SAFE(\
		(vn) = new_node_no_line();\
		(vn)->kind = NODE_NUMBER;\
		(vn)->type = TYPE_ANY;\
		)
#define CREATE_EXPR_NODE(vn, pn, f) SAFE(\
		(vn) = new_node_no_line();\
		(vn)->v.expr = pn;\
		(vn)->l.expr = vn;\
		(vn)->r.expr = 0;\
		(vn)->type = f;\
		)
#define CREATE_EXPR_LIST(vn, pn) SAFE(\
		(vn) = new_node();\
		(vn)->v.number = (pn ? ((parse_node_t *)pn)->kind : 0);\
		(vn)->l.expr = (pn ? ((parse_node_t *)pn)->l.expr : (vn));\
		(vn)->r.expr = pn;\
		)

/* tree functions */
void free_tree(void);
void release_tree(void);
/* node functions */
parse_node_t *new_node(void);
parse_node_t *new_node_no_line(void);
/* parser grammar functions */
parse_node_t *binary_int_op(parse_node_t *, parse_node_t *,
		char, char *);
parse_node_t *insert_pop_value(parse_node_t *);
parse_node_t *pop_value(parse_node_t *);
parse_node_t *optimize_loop_test(parse_node_t *);
int is_boolean(parse_node_t *);

#endif
